﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace helicopterFight
{
    /*
     * Klasa odpowiedzialna za obsługę kamery.
     */
    public class CameraTPP
    {
        private Vector3 cameraPosition;
        private Vector3 cameraLookAt;

        private Matrix cameraProjectionMatrix;
        public Matrix CameraProjectionMatrix
        {
            get { return cameraProjectionMatrix; }
            set { cameraProjectionMatrix = value; }
        }

        private Matrix cameraViewMatrix;
        public Matrix CameraViewMatrix
        {
            get { return cameraViewMatrix; }
            set { cameraViewMatrix = value; }
        }

        private Vector3 thirdPersonReference = new Vector3(0, 100, -500);    //TUTAJ USTAWIENIA KATA KAMERY
        private float scrollValue = 0;
        private float camRotation = 0;
        private float prevPosition = 0;
        
        private float zoomValue = 0.15f;
        public float ZoomValue
        {
            get { return zoomValue; }
            set { zoomValue = value; }
        }
        private const float maxZoomValue = 0.4f;
        public float MaxZoomValue
        {
            get { return maxZoomValue; }
        } 

        private const float minZoomValue = 0.05f;
        public float MinZoomValue
        {
            get { return minZoomValue; }
        } 

        private float   yaw = 0.0f, 
                        pitch = 0.0f,
                        roll = 0.0f;

        private const float angle = 0.02f;
        private float mx = 0, my = 0;

        MouseState ms;

        public CameraTPP()
        {
            cameraPosition = new Vector3(0.0f, 0.0f, 0.0f);
            cameraLookAt = new Vector3(0.0f, 0.0f, 10.0f);

            GameObject.cam = this;      //ustawia kamerę dla wszystkich obiektów, aby mogły pobrać sobie 
                                        //ViewMatrix i ProjectionMatrix
        }

        public void init(GraphicsDeviceManager graphics)
        {
            cameraViewMatrix = Matrix.CreateLookAt(cameraPosition, cameraLookAt, Vector3.Up);

            cameraProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(
                MathHelper.ToRadians(45.0f), graphics.GraphicsDevice.Viewport.AspectRatio, 1.0f, 10000.0f);

            mx = Mouse.GetState().X;
            my = Mouse.GetState().Y;
        }        

        public void Update()
        {            
            if (ms.RightButton == ButtonState.Released && Mouse.GetState().RightButton == ButtonState.Pressed)
            {
                mx = ms.X;
                my = ms.Y;
            }

            ms = Mouse.GetState();

            if (ms.RightButton == ButtonState.Pressed)
                rotateMouse();
            else            
                camBack();            
        }

        private void camBack()
        {
            if (yaw != 0)
            {
                yaw = yaw % (2 * (float)Math.PI);
                pitch = pitch % (2 * (float)Math.PI);

                if (yaw > Math.PI)
                    yaw = -1 * (2 * (float)Math.PI - yaw);
                if (yaw < (-1 * Math.PI))
                    yaw = -1 * (-2 * (float)Math.PI - yaw);

                if (Math.Round(yaw, 2) == 0)
                    yaw = 0;
                else
                    yaw = yaw * 0.95f;
            }
            if (pitch != 0)
            {
                if (pitch > Math.PI)
                    pitch = -1 * (2 * (float)Math.PI - pitch);
                if (pitch < (-1 * Math.PI))
                    pitch = -1 * (-2 * (float)Math.PI - pitch);

                if (Math.Round(pitch, 2) == 0)
                    pitch = 0;
                else
                    pitch = pitch * 0.95f;
            }
        }


        private void rotateMouse()
        {
            if (ms.X < mx)
                yaw -= angle*(mx - ms.X);
            if (ms.X > mx)
                yaw += angle * (ms.X - mx);
            if (ms.Y < my)
                pitch -= angle * (my - ms.Y);
            if (ms.Y > my)
                pitch += angle * (ms.Y - my);

            if (pitch > 1.15f) pitch = 1.15f;
            if (pitch < -1.94f) pitch = -1.94f;
                       
            mx = my = 100;
            Mouse.SetPosition(100, 100);       
        }

        private float zoom()
        {
            float zoomChange = 0;            

            if (scrollValue - ms.ScrollWheelValue != 0)
                if (scrollValue - ms.ScrollWheelValue > 0)
                {
                    zoomChange = 0.02f;                    
                }
                else
                {
                    zoomChange = -0.02f;                    
                }
            else
                return zoomValue;

            scrollValue = ms.ScrollWheelValue;
            zoomValue += zoomChange;

            if (zoomValue < minZoomValue) 
                zoomValue = minZoomValue;
            if (zoomValue > maxZoomValue)
                zoomValue = maxZoomValue;

            return zoomValue;
        }

        private void camPos(float position, float rotation)
        {
            if (ms.RightButton == ButtonState.Released)
            {
                if (camRotation - rotation != 0)
                    if (camRotation - rotation > 0)
                        yaw -= 0.02f;
                    else
                        yaw += 0.02f;
                camRotation = rotation;

                if (Math.Round(prevPosition - position) != 0 )
                    if (prevPosition - position > 0)
                    {
                        pitch += 0.01f;                        
                    }
                    else
                    {
                        pitch -= 0.01f;                        
                    }
                prevPosition = position;
            }
        }

        public void updateCamera(Vector3 position, Vector3 rotation) 
        {
            camPos(position.Y, rotation.Y);
            Matrix rotationMatrix = Matrix.CreateFromYawPitchRoll(rotation.Y - yaw, pitch, roll);
            Vector3 transformedReference = Vector3.Transform(thirdPersonReference, rotationMatrix) * zoom();
            Vector3 cameraPosition = transformedReference + position;
            cameraViewMatrix = Matrix.CreateLookAt(cameraPosition, position, Vector3.Up) ;           
        }

        public Vector3 getPos()
        {
            Matrix rotationMatrix = Matrix.CreateFromYawPitchRoll(-yaw, pitch, roll);
            return Vector3.Transform(thirdPersonReference, rotationMatrix) * zoom();            
        }
    }
}
